<html><head><meta charset="utf-8" /><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="" /><meta name="author" content="Maxim Sokhatsky" />
<title>EXE</title>
<link rel="stylesheet" href="https://n2o.dev/blank.css" />
<link rel="stylesheet" href="https://n2o.dev/zima.css" />
</head><body><nav>
        <a href="https://n2o.dev">DEV</a>
        <a href="https://exe.n2o.dev" style="background:#ededed;">EXE</a>
  <div class="dropdown">
    <a onclick="drop()" class="dropbtn">EN</a>
    <div id="dropdown" class="dropdown-content">
      <a href="https://n2o.dev/deps/exe/man/ua/index.html">UA</a>
      <a href="https://exe.n2o.dev/">EN</a>
    </div>
  </div>
    </nav><header>
        <a href="https://github.com/synrc/exe"><img src="https://openmoji.org/data/color/svg/1F4BB.svg"/></a>
        <h1>EXE</h1>
    </header><aside>
        <article>
            <section>
                <h3>SYNOPSIS</h3>
                <div>EXE is a family of functions and ports to interact with system shell, paths and external programs.
                </div><br/>
            <figure><code> $ mad get exe</code></figure>
            <br />
            <div>
                NOV 2021 © <a href="https://github.com/proger">proger</a> ISC
                VER 6.11 4.1 3.9
            </div>
            </section>
        </article>
    </aside><main>
    <section>
        <h3>MOTIVATION</h3>
        <p>Path clobbering and a reboot may happen here even email conforms RFC!</p>
        <figure><code>
 > Email = "proger+/&#38;reboot%23@hackndev.com".
 > os:cmd(["mkdir -p ", Email]).
        </code></figure>
        <p>So we can fix this with proper escaping, e.g.:</p>
        <figure><code>
 > Path = sh_path:escape("email+=/subdir@example.com").
 "email+=%2Fsubdir@example.com"
        </code></figure>
        <h3>ESSENCE</h3>
        <figure><code>
 reduce() -> fun({_, Chunk}, Acc) -> [Chunk|Acc] end.

 run(Args) ->
    erlang:open_port({spawn_executable, os:find_executable("sh")},
        [stream, in, out, eof, use_stdio, stderr_to_stdout, binary, exit_status,
            {args, ["-c",Args]}, {cd, element(2,file:get_cwd())}, {env, []}]).

 sh(Port) -> sh(Port, reduce(), []).
 sh(Port, Fun, Acc) -> receive
   {Port, {exit_status, Status}} -> 
          {done, Status, iolist_to_binary(lists:reverse(Acc))};
   {Port, {data, {eol, Line}}} ->
          sh(Port, Fun, Fun({eol, Line}, Acc));
   {Port, {data, {noeol, Line}}} ->
          sh(Port, Fun, Fun({noeol, Line}, Acc));
   {Port, {data, Data}} ->
          case { binary:match(Data, <<"Sign the certificate? [y/n]:">>) 
                 =/= nomatch,
                 binary:match(Data, <<"requests certified, commit?">>)
                 =/= nomatch} of
               { true , _} -> Port ! {self(),{command,<<"y\n">>}};
               { _ , true} -> Port ! {self(),{command,<<"y\n">>}};
               {_,_}       -> skip end,
          sh(Port, Fun, Fun({data,Data}, Acc)) end.
        </code></figure>
        <h3>USAGE</h3>
        <p>Family of functions and ports involving interacting with the system shell,
           paths and external programs.</p>
        <figure><code>
 > Url = "https://github.com/proger/darwinkit.git",
 > sh:run(["git", "clone", Url], binary, "/tmp").
 {done,0,&lt;&lt;"Cloning into 'darwinkit'...\n">>}
        </code></figure>
        <figure><code>
 > UserUrl = "https://github.com/proger/darwinkit.git".
 > sh:run(["git", "clone", UserUrl], binary, "/tmp").
 {done,128,
      &lt;&lt;"fatal: destination path 'darwinkit' ",
        "already exists and is not an empty directory.\n">>}
        </code></figure>
        <figure><code>
 > sh:run(["ifconfig"], "/tmp/output.log", "/tank/proger/vxz/otp").
 {done,0,"/tmp/output.log"}
        </code></figure>
        <figure><code>
 % cat /tmp/output.log
 >>> {{2013,8,28},{8,39,14}} /sbin/ifconfig
 lo0: flags=8049 mtu 16384
 	options=3
 	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
 	inet 127.0.0.1 netmask 0xff000000
 	inet6 ::1 prefixlen 128
 gif0: flags=8010 mtu 1280
 stf0: flags=0&lt;> mtu 1280
 en0: flags=8863 mtu 1500
	ether 7c:d1:c3:e9:24:65
	inet6 fe80::7ed1:c3ff:fee9:2465%en0 prefixlen 64 scopeid 0x4
	inet 192.168.63.163 netmask 0xfffffc00 broadcast 192.168.63.255
	media: autoselect
	status: active
 p2p0: flags=8843 mtu 2304
	ether 0e:d1:c3:e9:24:65
	media: autoselect
	status: inactive
 >>> {{2013,8,28},{8,39,14}} exit status: 0
        </code></figure>
        <figure><code>
 > sh:oneliner(["touch", filename:join("/tmp/", Path)]).
 {done,0,&lt;&lt;>>}
        </code></figure>
        <figure><code>
 > sh:oneliner("uname -mnprs").
 {done,0,&lt;&lt;"Darwin mac 18.2.0 x86_64 i386">>}
        </code></figure>
        <figure><code>
 > sh:oneliner("git describe --always").
 {done,128,&lt;&lt;"fatal: Not a valid object name HEAD">>}
        </code></figure>
        <figure><code>
 > sh:oneliner("git describe --always", "/tank/proger/vxz/otp").
 {done,0,&lt;&lt;"OTP_R16B01">>}
        </code></figure>
    </section>
    <section>
    <h3> FDLINK PORT</h3>

       <p>Consider a case of spawning a port that does not actually
          read its standard input (e.g. <b>socat</b> that bridges <b>AF_UNIX</b> with <b>AF_INET</b>):</p>

        <figure><code>
 # pstree -A -a $(pgrep beam.smp)
 beam.smp -- -root /usr/lib/erlang -progname erl -- -home /root -- -pa ebin -config sys.config
   |-socat tcp-listen:32133,reuseaddr,bind=127.0.0.1 unix-connect:/var/run/docker.sock
   `-16*[{beam.smp}]
        </code></figure>
        <p>If you terminate the node, <b>beam stdin</b> availability for you:</p>

        <figure><code>
 > Fdlink = sh:fdlink_executable().
 > erlang:open_port({spawn_executable, Fdlink},
   [stream, exit_status, {args, ["/usr/bin/socat"|Args]}).
        </code></figure>
        <p><b>fdlink</b> will also close the standard input of its child process.</p>
        <br /><br /><br />
    </section>
</main><footer>
    Made with <span class="heart">❤</span> to N2O
</footer>
<script>function drop(){document.getElementById("dropdown").classList.toggle("show");}</script>
</body></html>
